package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.XuechengPlusException;
import com.xuecheng.content.mapper.CourseTeacherMapper;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.mapper.TeachplanMediaMapper;
import com.xuecheng.content.model.dto.BindTeachplanMediaDto;
import com.xuecheng.content.model.dto.SaveTeachplanDto;
import com.xuecheng.content.model.dto.TeachPlanDto;
import com.xuecheng.content.model.po.Teachplan;
import com.xuecheng.content.model.po.TeachplanMedia;
import com.xuecheng.content.service.TeachPlanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
@Slf4j
public class TeachPlanServiceImpl implements TeachPlanService {
    @Autowired
    private TeachplanMapper teachplanMapper;
    @Autowired
    private TeachplanMediaMapper teachplanMediaMapper;
    @Autowired
    private CourseTeacherMapper courseTeacherMapper;

    /**
     * 查询课程计划
     * @param courseId
     * @return
     */
    @Override
    public List<TeachPlanDto> getTeachPlanTree(Long courseId) {
        return teachplanMapper.selectTreeNodeList(courseId);
    }

    /**
     * 新增/修改课程计划
     * @param saveTeachplanDto
     */
    @Override
    public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) {
        //业务逻辑
        //首先根据是否有课程计划id来判断是修改还是新增
        //1.先实现修改，修改简单一些
        if(saveTeachplanDto.getId() != null){
            Teachplan teachplan = teachplanMapper.selectById(saveTeachplanDto.getId());
            //使用beanUtils进行属性拷贝
            BeanUtils.copyProperties(saveTeachplanDto,teachplan);
            teachplanMapper.updateById(teachplan);
        }else{
            //2. 为新增操作，我们要新增，需要判断排序，排在第几位
            Teachplan teachplan = new Teachplan();
            BeanUtils.copyProperties(saveTeachplanDto,teachplan);
            //获取同一个父节点同一个课程的里面orderby的最大值
            //构建查询信息
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getCourseId,saveTeachplanDto.getCourseId())
                    .eq(Teachplan::getParentid,saveTeachplanDto.getParentid());
            Integer count = teachplanMapper.selectMax(queryWrapper) ;
            count = count == null ?  0 : count;
            //设置排序字段
            teachplan.setOrderby(count+1);
            //插入操作
            teachplanMapper.insert(teachplan);
        }
    }

    /**
     * 新增/修改课程计划
     * @param
     */
    @Override
    @Transactional
    public void deleteTeachplan(Long id) {
        //业务逻辑是要删除课程计划，并且要判断，如果该课程计划有子课程计划，则不允许删除
        //如果只有两级的话，我们可以用grade来判断 第二级的话可以直接删除并且删除相关媒资信息，对应的媒资表也要删除
        //但是现在想业务通用，我们同意判断该章节是否有子节点，如果没有可以删除，并且判断是否有媒资，如果有就删除媒资

        //先要根据id查询是否有子节点
        Teachplan teachplan = teachplanMapper.selectById(id);

        //判断是否为空
        if(teachplan == null){
            //如果为空，则直接返回
            return;
        }
        //判断是否有子节点 我们假设有多级别，统一来处理
        //构建查询条件
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getParentid,id);
        int count = teachplanMapper.selectCount(queryWrapper);
        if(count > 0){
            //如果有子节点，则不允许删除
            throw new RuntimeException("该节点有子节点，不允许删除");
        }

        //没有子节点，就要判断是否有媒资，有的话对应的表中也要删除
        //根据课程id删除
        teachplanMediaMapper.deleteByTeachplanId(id,teachplan.getCourseId());

        //删除计划表
        teachplanMapper.deleteById(id);

        //删除教师表
        //如果该课程删完了，需要删除课程信息表
        Integer integer = teachplanMapper.selectCount(new LambdaQueryWrapper<Teachplan>()
                .eq(Teachplan::getCourseId, teachplan.getCourseId()));
        if(integer == 0 || integer == null){
            courseTeacherMapper.deleteById(id);
        }

    }

    @Override
    @Transactional
    public void moveup(Long id) {
        //业务是课程上移，那我们要判断，如果当前课程的上一个课程，如果存在，则交换两个课程的顺序，并且还要更新两个课程的orderby字段
        //注意是同一grade下的课程 先查询
        Teachplan teachplan = teachplanMapper.selectById(id);
        if(teachplan == null){
            return;
        }
        //查询同一grade、courseid和parentid下的的上一个课程

        //我的思路是循环查询，每次查询的时候，将orderby-1，如果小于orderby<1的时候停止查询
        Teachplan teachplan1 = null;
        Integer orderby = teachplan.getOrderby();
        while(orderby > 1 && teachplan1 == null){
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid,teachplan.getParentid())
                    .eq(Teachplan::getGrade,teachplan.getGrade())
                    .eq(Teachplan::getCourseId,teachplan.getCourseId())
                    .eq(Teachplan::getOrderby,--orderby);

            teachplan1 = teachplanMapper.selectOne(queryWrapper);
        }
//        List<Teachplan> teachplans = teachplanMapper.list(teachplan.getCourseId(),teachplan.getParentid(),teachplan.getGrade());
        if(teachplan1 == null){
            throw new XuechengPlusException("已经到顶啦~~~~~");
        }

        orderby = teachplan.getOrderby();
        teachplan.setOrderby(teachplan1.getOrderby());
        teachplan1.setOrderby(orderby);
        teachplanMapper.updateById(teachplan);
        teachplanMapper.updateById(teachplan1);
    }

    /**
     * 课程计划下移
     * @param id
     */
    @Override
    public void movedown(Long id) {
        //业务是课程下移，那我们要判断，如果当前课程的下一个课程，如果存在，则交换两个课程的顺序，并且还要更新两个课程的orderby字段
        //注意是同一grade下的课程 先查询
        Teachplan teachplan = teachplanMapper.selectById(id);
        if(teachplan == null){
            return;
        }
        //获取到同一级别，同一course_id，同一parentid下的最大值
        Integer max = teachplanMapper.selectMax(new LambdaQueryWrapper<Teachplan>()
                .eq(Teachplan::getParentid,teachplan.getParentid())
                .eq(Teachplan::getGrade,teachplan.getGrade())
                .eq(Teachplan::getCourseId,teachplan.getCourseId()));

        //开始下移
        Teachplan teachplan1 = null;
        Integer orderby = teachplan.getOrderby();

        while(orderby < max && teachplan1 == null){
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid,teachplan.getParentid())
                    .eq(Teachplan::getGrade,teachplan.getGrade())
                    .eq(Teachplan::getCourseId,teachplan.getCourseId())
                    .eq(Teachplan::getOrderby,++orderby);
            teachplan1 = teachplanMapper.selectOne(queryWrapper);
        }
        if(teachplan1 == null){
            throw new XuechengPlusException("已经到底啦~~~~~");
        }
        orderby = teachplan.getOrderby();
        teachplan.setOrderby(teachplan1.getOrderby());
        teachplan1.setOrderby(orderby);

        teachplanMapper.updateById(teachplan);
        teachplanMapper.updateById(teachplan1);
    }

    /**
     * 课程计划与媒资文件的绑定
     * @param bindTeachplanMediaDto 课程计划与媒资文件的绑定信息
     */
    @Override
    @Transactional
    public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto) {
        //其实就是向计划媒资表中加入该条记录，并且计划表中媒资类型为 001002 为视频
        //先查询该计划
        Long teachplanId = bindTeachplanMediaDto.getTeachplanId();
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);
        if(teachplan == null){
            XuechengPlusException.cast("课程计划不存在");
        }
        //只有二级目录可以绑定
        if(teachplan.getGrade() != 2){
            XuechengPlusException.cast("只允许二级课程计划绑定媒资文件");
        }

        teachplan.setMediaType("001002");

        //如果在计划媒资表中已经绑定过了 则返回
        TeachplanMedia teachplanMedia = teachplanMediaMapper.selectByTeachplanId(teachplanId);
        if(teachplanMedia != null){
            XuechengPlusException.cast("该课程计划已绑定媒资文件");
        }

        teachplanMedia = new TeachplanMedia();
        BeanUtils.copyProperties(bindTeachplanMediaDto,teachplanMedia);
        teachplanMedia.setCourseId(teachplan.getCourseId());
        teachplanMedia.setMediaFilename(bindTeachplanMediaDto.getFileName());
        teachplanMedia.setCreateDate(LocalDateTime.now());
        teachplanMediaMapper.insert(teachplanMedia);

        //最后再来更新计划表
        teachplanMapper.updateById(teachplan);
    }

    @Override
    public void deleteAssociationMedia(Long teachplanId, String mediaId) {

        //删除计划媒资表中的记录
        teachplanMediaMapper.deleteMedia(teachplanId,mediaId);
    }
}
